package vip.indo.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: tianlianyin
 * @Date: 2024/11/28 13:23
 * @Descripition:
 */
@Aspect
@Component
@Slf4j
public class LogAspectHandler {
    /**
     * 定义一个切面，拦截Controller包下的所有方法
     */
    @Pointcut("execution(* vip.indo.controller..*.*(..))")
    public void pointcut() {
    }

    /**
     * 给注解的切面
     */
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void annotationCut() {
    }

    /**
     * 切面前置通知，在方法执行前触发，记录日志
     *
     * @param joinPoint
     */
    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("====doBefore方法进入了====");
        //获取签名
        Signature signature = joinPoint.getSignature();
        //获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        //获取即将执行的方法名
        String funName = signature.getName();
        log.info("即将执行的方法为：{}，输入{}包", funName, declaringTypeName);
        //也可以用来记录一些信息，比如获取请求的url和ip
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            //获取请求url
            HttpServletRequest request = attributes.getRequest();
            //获取请求url
            String url = request.getRequestURL().toString();
            //获取请求IP
            String ip = request.getRemoteAddr();
            log.info("用户请求的url为：{}，请求的IP为：{}", url, ip);
        }
    }

    /**
     * 在上面的切面前置通知执行完之后，会执行下面的切面
     *
     * @param joinPoint
     */
    @After("pointcut()")
    public void doAfter(JoinPoint joinPoint) {
        log.info("====doAfter方法进入了====");
        Signature signature = joinPoint.getSignature();
        //获取即将执行的方法名
        String method = signature.getName();
        log.info("方法{}已经执行完成", method);
    }

    /**
     * 在上面定义的切面方法返回后执行该方法，可以捕获返回对象或者对返回对象进行增强
     *
     * @param joinPoint
     * @param result
     */
    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        Signature signature = joinPoint.getSignature();
        String classMethod = signature.getName();
        log.info("方法{}执行完毕，返回参数为：{}", classMethod, result);
        //实际项目中可以根据业务做具体的返回值数据
        log.info("对返回参数进行业务上的增强：{}", result + "增强版");
    }

    /**
     * 在方法抛出异常后执行该方法
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(pointcut = "pointcut()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Throwable ex){
        Signature signature=joinPoint.getSignature();
        String method=signature.getName();
        //处理异常的逻辑
        log.info("方法{}执行异常了，异常为：{}", method,ex.toString());
    }
}
